#pragma once
#ifndef __G_CORE_H__
#define __G_CORE_H__

#include <atomic>
#include <string>
#include <unordered_map>

#include "GTypes.h"
#include "GWindow.h"
#include "GSingleton.h"
#include "GInitializable.h"
#include "GMessageHandler.h"


namespace GEngine
{
	// Forward declarations of module/manager types
	class GApplication;
	class GInputModule;
	class GSoundModule;
	class GPhysicModule;
	class GGraphicModule;
	class GNetworkModule;


	class GAIManager;
	class GTransformManager;
	class GAnimationManager;
	class GScriptManager;
	class GResourceManager;
	

	class GCore : public GUtil::GInitializable, public GUtil::GSingleton<GCore>
	{
	friend class GUtil::GSingleton<GCore>;

	typedef std::atomic_bool AtomicBool;
	typedef std::unordered_map<std::string, GWindow*, std::hash<std::string>, std::equal_to<std::string>> WindowMapType;

	private:
		AtomicBool			ExitSwitch;

		GApplication*		AppModule;
		GInputModule*		InputModule;
		GSoundModule*		SoundModule;
		GPhysicModule*		PhysicModule;
		GGraphicModule*		GraphicModule;
		GNetworkModule*		NetworkModule;

							GCore();
		virtual				~GCore();
	
		void				MainLoop();

		bool				CreateAppModule();
		bool				CreateInputModule();
		bool				CreateSoundModule();
		bool				CreatePhysicModule();
		bool				CreateGraphicModule();
		bool				CreateNetworkModule();

	public:
		void				Run();
		void				Exit();

		GApplication*		GetAppModule() const;
		GInputModule*		GetInputModule() const;
		GSoundModule*		GetSoundModule() const;
		GPhysicModule*		GetPhysicModule() const;
		GGraphicModule*		GetGraphicModule() const;
		GNetworkModule*		GetNetworkModule() const;

		bool				Initialize() OVERRIDE;
		bool				InitializeLate() OVERRIDE;
		
		void				Uninitialize() OVERRIDE;
		void				UninitializeEarly() OVERRIDE;
		
	};

}

#define mGCore				GEngine::GCore::GetInstance()
#define mGAppModule			GEngine::GCore::GetInstance()->GetAppModule()

//! Move these to the managers when they are implemented
#define mGSoundModule		GEngine::GCore::GetInstance()->GetSoundModule()
#define mGPhysicModule		GEngine::GCore::GetInstance()->GetPhysicModule()
#define mGGraphicModule		GEngine::GCore::GetInstance()->GetGraphicModule()
#define mGNetworkModule		GEngine::GCore::GetInstance()->GetNetworkModule()

#endif